Day 7 到 Day 11 那幾篇的結論很明確:AI 產出的東西要被驗證。
而現在這個知識庫,本身就是 AI 幫忙產出的。
所以結論只有一個:它當然也要被驗。
而且不能是我每次手動看一遍——那就回到 Day 2 那個「規模是 O(票數 × 人力)」的死路。必須自動。
現在有一支很小的檢查腳本,做的事情其實很基本:
sourceRaw)這些都是很土的檢查,但它們擋的是最容易發生、也最難察覺的那類問題:東西靜悄悄地少了一塊。
這是我真正想處理的部分。Day 9 講的三類錯誤,逐一評估:
| 錯誤類型 | 能不能自動驗 | 怎麼驗 |
|---|---|---|
| 憑空生成的編號 | ✅ 容易 | 把所有編號抽出來,打 API 查存不存在。五秒鐘的事 |
數值錯置(< 2 變成 < 6) |
✅ 低成本高回報 | 抽出所有門檻類的數字(閾值、上限、天數、筆數)→ 去程式碼裡比對 → 不一致就標紅 |
| 功能 ↔ 頁面歸屬 | ⚠️ 難全自動 | 但可以偵測「同一個功能名出現在多個頁面」,標記成待人工確認 |
第二行是我最滿意的一個發現。
因為 Day 9 那個 < 2 變成 < 6,當時我以為它是一種很難防的錯——它通過所有查證,每個零件都是真的。
但如果換一個角度:門檻數字這種東西,格式特徵非常明顯。 它就是一個數字,旁邊跟著一個比較符號。抽出來很容易,而程式碼裡的對應值也很容易找。
一個看起來很難防的錯,只要換一個切入點,就變成一條正規表達式加一次比對。
第三行沒辦法全自動,但我想強調那個折衷的價值:它做不到「判斷這個功能屬於哪一頁」,但它做得到「這個功能被寫在三個頁面上,請人看一下」。
抓不到錯,至少不要讓它默默地錯下去。
一個被標記出來的可疑項,跟一個沒有人知道的錯誤,是完全不同等級的東西。
上面那些驗的都是同一件事:知識庫裡的內容對不對。
而我後來想加的兩項,都在另一端:
第一,錯字。使用者搜尋的時候打錯字怎麼辦?
第二,斷句。如果所有文字都黏在一起,能不能判斷出他要問什麼?
這兩項跟內容正確性一點關係都沒有。它們問的是:當使用者問得歪歪的,這個東西還找不找得到?
我想像的使用情境,不是一個人端正地坐著,輸入一個文法完整的問題。
實際上會發生的是:一個人在測試中途卡住,一手還按著滑鼠,隨手打了幾個關鍵字進去。錯字、漏字、沒有標點、全部黏在一起。
而如果這時候撈不出東西,那個人會得到的結論是:「這裡面沒有。」
不是「我打錯了」,是「這個知識庫沒有這個東西」。
這兩個結論的差別非常大。第一個他會再試一次,第二個他就走了——而且他會帶著一個錯的印象:這東西不好用。
Day 13 我寫過,一份文件最常見的死法是沒有人知道它在。第二常見的死法,大概就是有人試過一次、沒撈到、然後就不再回來了。
Day 13 講過,我做了一個不依賴模型的靜態版本。
我原本以為那邊的失敗會是全有全無的:打對了命中,打錯一個字就是零。
後來我實際去測,發現不是那樣——而且比那樣更糟。
我拿幾個問題,各打錯一個字再查一次。結果是:每一次都還是回了六筆,一筆都沒少。 因為中文是切成二字一組去比對的,錯一個字只會少命中幾組,其他照樣中。
但第一名變成了錯的那一筆,分數也掉了一半以上。
所以真正的失敗模式不是「查不到」,是:
它給你六筆看起來很正常的東西,而你要的那一筆不在第一個。
全有全無至少是誠實的——使用者知道自己沒找到,他會再試一次。
而現在這個,他不會知道。
這跟 Day 9 那個第三類錯誤是同一種病:每個零件都是真的,只是排錯了位置,而且讀起來完全正常。
而這件事我現在還沒解決。
把上面的東西整理一下,會發現要驗的是兩件不同性質的事:
| 驗什麼 | 失敗長什麼樣子 | |
|---|---|---|
| 正確性 | 知識庫裡寫的對不對 | 它給了一個錯的答案 |
| 韌性 | 使用者問歪了還找不找得到 | 它說「查不到」,而東西其實在裡面 |
而我想講的是——第二種失敗,我原本根本沒有把它當成失敗。
因為從系統的角度看,「查不到」不是錯誤。它沒有當掉、沒有亂講、沒有幻覺。它誠實地說了「我沒有資料」。
但從使用者的角度看,那跟「這東西沒用」是一樣的。
一個從來不出錯、但常常找不到的知識庫,跟一個不存在的知識庫,在體感上差距沒有想像中大。
寫到這裡我意識到,這整篇其實是一個很典型的 QA 思路,而它有兩條:
第一條:任何產出物都要有一個「壞掉的時候會紅」的檢查。
不是「我看過了覺得沒問題」,是如果有人把它改壞了,會有一個東西自動變紅。這條標準我套用在程式碼上很多年了,而這次我只是把它套到一份文件上。
第二條:不要只測乖乖的輸入。
一個功能只用正確的輸入測過,那不叫測過。真正的測試要放邊界、放負向、放不合理的東西進去——因為真實世界就是那樣。
而我發現,我在做這個知識庫的時候,前半段一直在用第一條,卻忘了第二條。
我很認真地驗證了裡面的每一條事實對不對,卻預設使用者會好好地提問。
那是一個 QA 不該犯的錯。
今天講的是想加還沒加的檢查。
但有一種「故意為難它」的測試,我倒是很早就做了——而且做得滿狠的:我在餵給它的資料裡,放了幾條完全無關的東西。
那個測試後來變成整個系列裡最戲劇化的一段。不過在講那個之前,得先交代一件事:
我到底為什麼會選擇在自己的筆電上跑模型?
那是明天的題目。